package com.revai.engine.basic.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import org.springframework.context.ApplicationContext;

import com.revai.engine.basic.core.ApplicationContextProvider;
import com.revai.engine.basic.service.ClassCacheService;

import cn.hutool.core.util.ReflectUtil;

public class ExampleCriteria {

    private Object criteria;

    private Class<?> criteriaClazz;

    private Class<?> modelClass;

    private Class<?> mapperClass;

    private Class<?> exampleClass;

    private Object exampleObject;

    public ExampleCriteria(String tableName, ClassCacheService classCache) throws Exception {
        String modelName = StrUtils.toClassCamelCase(tableName);
        modelClass = classCache.getModelClass(tableName);
        exampleClass = classCache.getExampleClass(tableName);
        mapperClass = classCache.getMapperClass(tableName);

        // 查询实例
        exampleObject = exampleClass.newInstance();
        Method criteriaMethod = exampleClass.getMethod("createCriteria");
        criteria = criteriaMethod.invoke(exampleObject);
        Class<?>[] clazzes = exampleClass.getDeclaredClasses();
        for (Class<?> clazz : clazzes) {
            // 使用Criteria构建自动查询条件
            if ((ConstConfig.BASEPACKAGEMODEL + modelName + "Example$Criteria").equals(clazz.getName())) {
                criteriaClazz = clazz;
            }
        }
    }

    public ExampleCriteria(String tableName) throws Exception {
        String modelName = StrUtils.toClassCamelCase(tableName);
        modelClass = Class.forName(ConstConfig.BASEPACKAGEMODEL + modelName);
        exampleClass = Class.forName(ConstConfig.BASEPACKAGEMODEL + modelName + "Example");
        mapperClass = Class.forName(ConstConfig.BASEPACKAGEMAPPER + modelName + "Mapper");

        // 查询实例
        exampleObject = exampleClass.newInstance();
        Method criteriaMethod = exampleClass.getMethod("createCriteria");
        criteria = criteriaMethod.invoke(exampleObject);
        Class<?>[] clazzes = exampleClass.getDeclaredClasses();
        for (Class<?> clazz : clazzes) {
            // 使用Criteria构建自动查询条件
            if ((ConstConfig.BASEPACKAGEMODEL + modelName + "Example$Criteria").equals(clazz.getName())) {
                criteriaClazz = clazz;
            }
        }
    }

    public Object getExample() {
        return exampleObject;
    }

    /**
     * 执行查询
     * 
     * @return
     * @throws Exception
     */
    public Object selectByExample() throws Exception {
        ApplicationContext applicationContext = ApplicationContextProvider.getContext();
        // 获取mapper
        Object bean = applicationContext.getBean(mapperClass);
        // 获取mapper的查询方法
        Method selectMethod = mapperClass.getMethod("selectByExample", exampleClass);
        return selectMethod.invoke(bean, exampleObject);
    }

    /**
     * 执行查询
     * 
     * @return
     * @throws Exception
     */
    public Object countByExample() throws Exception {
        ApplicationContext applicationContext = ApplicationContextProvider.getContext();
        // 获取mapper
        Object bean = applicationContext.getBean(mapperClass);
        // 获取mapper的查询方法
        Method selectMethod = mapperClass.getMethod("countByExample", exampleClass);
        return selectMethod.invoke(bean, exampleObject);
    }

    /**
     * 执行删除
     * 
     * @return
     * @throws Exception
     */
    public Object deleteByExample() throws Exception {
        ApplicationContext applicationContext = ApplicationContextProvider.getContext();
        // 获取mapper
        Object bean = applicationContext.getBean(mapperClass);
        // 获取mapper的查询方法
        Method selectMethod = mapperClass.getMethod("deleteByExample", exampleClass);
        return selectMethod.invoke(bean, exampleObject);
    }

    /**
     * 更新
     * 
     * @param row
     * @return
     * @throws Exception
     */
    public Object updateByExample(Object row) throws Exception {
        ApplicationContext applicationContext = ApplicationContextProvider.getContext();
        // 获取mapper
        Object bean = applicationContext.getBean(mapperClass);
        // 获取mapper的查询方法
        Method selectMethod = mapperClass.getMethod("updateByExampleSelective", modelClass, exampleClass);
        return selectMethod.invoke(bean, row, exampleObject);
    }

    /**
     * 执行In方法
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    public void andIn(String key, List<?> values) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            // Field field = modelClass.getDeclaredField(key);
            // Class<?> type = field.getType();
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "In", List.class);
            exampleMethod.invoke(criteria, values);
        }
    }

    /**
     * 执行EqualTo方法
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    public void andEqualTo(String key, Object value) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            // System.err.println(String.format("fieldName: %s, type: %s， value: %s", fieldName, type, value));
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "EqualTo", type);
            exampleMethod.invoke(criteria, value);
            
        }
    }

    /**
     * 执行Like方法
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    public void andLike(String key, Object value) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "Like", type);
            exampleMethod.invoke(criteria, "%" + value + "%");
        }
    }

    /**
     * 执行Between方法
     * 
     * @param key
     * @param startValue
     * @param endValue
     * @throws Exception
     */
    public void andBetween(String key, Object startValue, Object endValue) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "Between", type, type);
            exampleMethod.invoke(criteria, startValue, endValue);
        }
    }

    /**
     * 执行GreaterThanOrEqualTo方法
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    public void andGreaterThanOrEqualTo(String key, Object value) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "GreaterThanOrEqualTo", type);
            exampleMethod.invoke(criteria, value);
        }
    }

    /**
     * 执行LessThanOrEqualTo方法
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    public void andLessThanOrEqualTo(String key, Object value) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "LessThanOrEqualTo", type);
            exampleMethod.invoke(criteria, value);
        }
    }

    /**
     * 执行NotEqualTo方法
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    public void andNotEqualTo(String key, Object value) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            String fieldName = StrUtils.toFieldCamelCase(key);
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            Method exampleMethod = criteriaClazz.getMethod("and" + fieldName + "NotEqualTo", type);
            exampleMethod.invoke(criteria, value);
        }
    }

    /**
     * 获取字段类型
     * 
     * @param key
     * @return
     * @throws Exception
     */
    public String getFieldTypeName(String key) throws Exception {
        if (ReflectUtil.hasField(modelClass, key)) {
            Field field = modelClass.getDeclaredField(key);
            Class<?> type = field.getType();
            return type.getName();
        }
        return null;
    }
}
